package mapper

import (
	"errors"
	"fmt"
	"reflect"
	"strings"

	"gitee.com/rainsuperman/mapper_orm/mapper_core"
)

type WhereSql struct {
	columnName string //字段名
	whereType  string //查询类型，如=，>，<，like等
	whereValue []any  //查询值
}

const (
	FromTypeNo            = 0   //未指定
	FromTypeT             = 100 //fromT类型
	FromTypeStr           = 200 //from 字符串
	FromTypeChild         = 300 //from 子查询
	FromTypeUnion         = 400 //from 联合查询
	FromTypeUnionAll      = 500 //from 联合查询所有
	FromTypeUnionDistinct = 600 //from 联合查询去重
)

type MapperQuery struct {
	excludeSelect              []string
	selectList                 []string
	selectWithMapperList       []MapperQuery
	selectWithMapperListAsName []string

	fromType         int //未指定0 fromT类型100，fromStr 200，fromChild 300，fromUnion 400，fromUnionAll 500，fromUnionDistinct 600
	fromType200Str   string
	fromTypeGenerics DbEntity //fromT类型的泛型

	joinBaseTableAsName *string
	joinInfo            []string //join信息

	enableMarkDel bool //是否生效逻辑删除
	whereMap      []WhereSql
	childQueries  []MapperQuery //子查询

	orderBy  []string
	groupBy  string
	having   string
	last     string
	pageMark *string
}

func NewQuery() *MapperQuery {

	m := MapperQuery{}
	m.fromType = FromTypeNo
	m.enableMarkDel = true
	return &m
}

func NewQueryWithT[T DbEntity]() *MapperQuery {
	m := MapperQuery{}
	var tt T
	m.fromTypeGenerics = tt
	m.fromType = FromTypeT
	m.enableMarkDel = true
	return &m
}

func (m MapperQuery) DisableMarkDel() *MapperQuery {
	m.enableMarkDel = false
	return &m
}

func FinalStr(m MapperQuery) (string, []any, error) {

	sqlSelectStr, argSelect, err := FinalSelectStr(m)
	if err != nil {
		return "", nil, err
	}

	sqlFromStr, argsFrom, err := FinalFromStr(m)
	if err != nil {
		return "", nil, err
	}

	sqlEndStr, argsEnd, err := FinalEndStr(m, true, true)
	if err != nil {
		return "", nil, err
	}

	return "SELECT " + sqlSelectStr + sqlFromStr + sqlEndStr, append(append(argSelect, argsFrom...), argsEnd...), nil

}

// 组装SELECT语句中要查询的字段
func FinalSelectStr(m MapperQuery) (string, []any, error) {

	reArg := []any{}

	aStart := "" //基准表别名

	if len(m.joinInfo) > 0 {
		if m.joinBaseTableAsName == nil { //如果没有指定别名，使用默认别名
			aStart = GetConfig().JoinBaseTableAsName + "."
		} else {
			aStart = *m.joinBaseTableAsName + "."
		}
	}

	haveA := false //是否包含基准表中的字段  如果已有基准表中的字段就不解析表  否则需要解析表

	sqlSelectStr := ""

	if len(m.selectList) > 0 { //有指定查询字段，使用指定的字段
		for i := range m.selectList {
			sqlSelectStr += m.selectList[i] + ","
			if strings.HasPrefix(m.selectList[i], aStart) {
				haveA = true
			}
		}
		if aStart == "" {
			haveA = true
		}
	}

	if haveA { //已包含基准表中的字段  则不解析表  忽略基准表排除字段

		reStr, args, err := finalSelectStrChild(m)
		if err != nil {
			return sqlSelectStr, reArg, err
		}
		sqlSelectStr += reStr
		reArg = append(reArg, args...)

		sqlSelectStr = sqlSelectStr[:len(sqlSelectStr)-1]
		return sqlSelectStr, reArg, nil
	}

	if m.fromType != FromTypeT {

		reStr, args, err := finalSelectStrChild(m)
		if err != nil {
			return sqlSelectStr, reArg, err
		}
		sqlSelectStr += reStr
		reArg = append(reArg, args...)

		if len(sqlSelectStr) == 0 {
			return sqlSelectStr, reArg, errors.New("至少要有一个查询.字段")
		}

		sqlSelectStr = sqlSelectStr[:len(sqlSelectStr)-1]

		return sqlSelectStr, reArg, nil
	}

	//需要解析表  添加基准表的字段

	if m.fromTypeGenerics == nil {
		return "", reArg, errors.New("未指定查询来源类型")
	}

	reflectType := reflect.TypeOf(m.fromTypeGenerics)
	sqlSelectStr += baseTableCloStr(m, reflectType)

	reStr, args, err := finalSelectStrChild(m)
	if err != nil {
		return sqlSelectStr, reArg, err
	}
	sqlSelectStr += reStr
	reArg = append(reArg, args...)

	if len(sqlSelectStr) == 0 {
		return sqlSelectStr, reArg, errors.New("至少要有一个查询..字段")
	}

	sqlSelectStr = sqlSelectStr[:len(sqlSelectStr)-1]

	return sqlSelectStr, reArg, nil
}

func finalSelectStrChild(m MapperQuery) (string, []any, error) {

	reArg := []any{}
	reStr := ""

	//处理复杂mapper
	if len(m.selectWithMapperList) > 0 {
		for i := range m.selectWithMapperList {
			selectStr, args, err := FinalStr(m.selectWithMapperList[i])
			if err != nil {
				return "", nil, err
			}
			reStr += fmt.Sprintf("\n(%s) as %s,", selectStr, m.selectWithMapperListAsName[i])
			reArg = append(reArg, args...)
		}
	}
	return reStr, reArg, nil
}

// 组装FROM语句
// 之所以要返回[]any 是因为from语句中可能会有子查询会携带参数
func FinalFromStr(m MapperQuery) (string, []any, error) {

	var args []any //返回的参数
	oriTableInfo := ""

	if m.fromType == FromTypeT { //fromT类型

		if m.fromTypeGenerics == nil {
			return "", nil, errors.New("未指定查询来源类型")
		}
		oriTableInfo = m.fromTypeGenerics.TableName()
	} else if m.fromType == FromTypeStr { // from字符串类型
		oriTableInfo = m.fromType200Str
	} else if m.fromType == FromTypeChild { // from子查询类型
		sqlFromStr := "  ( \nSELECT "

		selectStr, argSelect, err := FinalSelectStr(m.childQueries[0])
		if err != nil {
			return "", []any{}, err
		}
		args = append(args, argSelect...)

		sqlFromStr += selectStr

		bb, argFrom, err := FinalFromStr(m.childQueries[0])
		if err != nil {
			return "", nil, err
		}
		sqlFromStr += bb
		args = append(args, argFrom...)
		aa, argEnd, _ := FinalEndStr(m.childQueries[0], true, true)
		sqlFromStr += aa
		args = append(args, argEnd...)
		sqlFromStr += " \n) "

		if len(m.joinInfo) == 0 {

			if m.joinBaseTableAsName == nil { //如果没有指定别名，使用默认别名

				m.joinBaseTableAsName = &GetConfig().JoinBaseTableAsName
			}
			sqlFromStr += *m.joinBaseTableAsName + " "

		}
		oriTableInfo = sqlFromStr
	} else {

		sqlFromStr := " (\n"

		for i := range m.childQueries {
			sqlFromStr += " SELECT "
			selectStr, argSelect, err := FinalSelectStr(m.childQueries[i])
			if err != nil {
				return "", []any{}, err
			}
			args = append(args, argSelect...)
			sqlFromStr += selectStr
			bb, argFrom, err := FinalFromStr(m.childQueries[i])
			if err != nil {
				return "", []any{}, err
			}

			sqlFromStr += bb
			args = append(args, argFrom...)
			aa, argEnd, _ := FinalEndStr(m.childQueries[i], true, true)
			sqlFromStr += aa
			args = append(args, argEnd...)

			if i < len(m.childQueries)-1 {

				if m.fromType == 400 { //union
					sqlFromStr += " \n UNION \n"
				} else if m.fromType == 500 { //unionAll
					sqlFromStr += "\n UNION ALL \n"
				} else if m.fromType == 600 { //unionDistinct
					sqlFromStr += "\n UNION DISTINCT \n"
				}
			}

		}

		sqlFromStr += " \n) "

		if len(m.joinInfo) == 0 {

			if m.joinBaseTableAsName == nil { //如果没有指定别名，使用默认别名

				m.joinBaseTableAsName = &GetConfig().JoinBaseTableAsName
			}
			sqlFromStr += *m.joinBaseTableAsName + " "

		}

		oriTableInfo = sqlFromStr + "\n"
	}

	if len(m.joinInfo) > 0 { //有连表查询

		if m.joinBaseTableAsName == nil { //如果没有指定别名，使用默认别名

			m.joinBaseTableAsName = &GetConfig().JoinBaseTableAsName
		}

		sqlFromStr := " \n FROM " + oriTableInfo + " " + *m.joinBaseTableAsName + " "

		for i := range m.joinInfo {
			sqlFromStr += m.joinInfo[i] + " "
		}

		return sqlFromStr, args, nil
	}

	return " \n FROM " + oriTableInfo, args, nil
}

// 组装最终的SQL语句
// withOrderBy 是否包含orderBy
// withLast 是否包含last
func FinalEndStr(m MapperQuery, withOrderBy, withLast bool) (string, []any, error) {

	sqlEndStr := " "
	var args []any

	whereOrAnd := " WHERE "

	//处理where条件
	if len(m.whereMap) > 0 {
		str, arg := dealWhere(m.whereMap)
		args = append(args, arg...)

		sqlEndStr += whereOrAnd + str

		whereOrAnd = " AND "
	}

	//TODO 统一处理 处理逻辑删除
	if GetConfig().MarkDelColumnName != "" && m.enableMarkDel {

		if len(m.joinInfo) > 0 {

			if m.joinBaseTableAsName == nil { //如果没有指定别名，使用默认别名
				m.joinBaseTableAsName = &GetConfig().JoinBaseTableAsName
			}

			sqlEndStr += whereOrAnd + " (" + *m.joinBaseTableAsName + "." + GetConfig().MarkDelColumnName + " = 0)"

			whereOrAnd = " AND "
		} else {

			sqlEndStr += whereOrAnd + " (" + GetConfig().MarkDelColumnName + " = 0)"

			whereOrAnd = " AND "
		}

	}

	//处理groupBy
	if withOrderBy && len(m.groupBy) > 0 {
		sqlEndStr += " \n GROUP BY " + m.groupBy
		//args = append(args, m.groupBy)

	}

	//处理having
	if withOrderBy && len(m.having) > 0 {
		sqlEndStr += " \n HAVING " + m.having

	}

	//处理orderBy
	if withOrderBy && len(m.orderBy) > 0 {
		for i := range m.orderBy {

			if i == 0 {
				sqlEndStr += " \n ORDER BY " + m.orderBy[i]

			} else if i < len(m.orderBy)-1 {
				sqlEndStr += " , "
			} else {
				sqlEndStr += "," + m.orderBy[i]
			}
			//sqlEndStr += " ? "
			//args = append(args, m.orderBy[i])
		}

	}

	//处理last
	if withLast && m.last != "" {
		sqlEndStr += " " + m.last + " "
	}

	if withLast && m.pageMark != nil {
		sqlEndStr += " " + *m.pageMark + " "
	}

	return sqlEndStr, args, nil
}

func baseTableCloStr(m MapperQuery, reflectType reflect.Type) string {
	sqlSelectStr := ""
	tableInfos := mapper_core.GetTabelInfo(reflectType)

	for i := range tableInfos {

		//去除基准表中所有字段
		if len(m.excludeSelect) == 1 && m.excludeSelect[0] == "*" {
			continue
		}

		//去除基准表中指定字段
		fl := false
		if len(m.excludeSelect) > 0 {
			for j := range m.excludeSelect {
				if tableInfos[i].ColumnName == m.excludeSelect[j] {
					fl = true
				}
			}
		}
		if fl {
			continue
		}

		if len(m.joinInfo) > 0 {

			if m.joinBaseTableAsName == nil { //如果没有指定别名，使用默认别名
				m.joinBaseTableAsName = &GetConfig().JoinBaseTableAsName
			}

			sqlSelectStr += *m.joinBaseTableAsName + "." + tableInfos[i].ColumnName + ","
		} else {
			sqlSelectStr += tableInfos[i].ColumnName + ","

		}

	}

	return sqlSelectStr
}

// 返回where条件字符串,参数列表
func dealWhere(whereMap []WhereSql) (string, []any) { //where a=1 or b=3 and (c=4 or d=5 or (e=6 or f=7) ) or (e=6 or f=7)
	whereStr := " "
	var args []any

	whereOrAnd := " "

	for i := range whereMap {

		if whereMap[i].whereType == "OR" {

			whereOrAnd = " OR "
			if whereMap[i].whereValue == nil {

			} else {
				childWhere := whereMap[i].whereValue[0].(MapperQuery)
				whereStr += whereOrAnd + " ( "
				str, arg := dealWhere(childWhere.whereMap) //递归处理子查询
				args = append(args, arg...)

				whereStr += str
				whereStr += " ) "

				whereOrAnd = " AND "
			}

		} else if whereMap[i].whereType == "AND" {

			childWhere := whereMap[i].whereValue[0].(MapperQuery)
			whereStr += whereOrAnd + " ( "
			str, arg := dealWhere(childWhere.whereMap) //递归处理子查询
			args = append(args, arg...)

			whereStr += str
			whereStr += " ) "

			whereOrAnd = " AND "

		} else if whereMap[i].whereType == "IN" || whereMap[i].whereType == "NOT IN" {

			whereStr += whereOrAnd
			whereOrAnd = " AND "
			whereStr += whereMap[i].columnName + " " + whereMap[i].whereType + " ( "

			for _, val := range whereMap[i].whereValue {

				whereStr += " ?,"
				args = append(args, fmt.Sprintf("%v", val))
			}
			whereStr = whereStr[:len(whereStr)-1] //去除最后一个逗号

			whereStr += " ) "

		} else if whereMap[i].whereType == "IS NULL" || whereMap[i].whereType == "IS NOT NULL" {

			whereStr += whereOrAnd
			whereOrAnd = " AND "
			whereStr += "? " + whereMap[i].whereType

			args = append(args, whereMap[i].columnName)

		} else if whereMap[i].whereType == "BETWEEN" {

			whereStr += whereOrAnd
			whereOrAnd = " AND "
			whereStr += whereMap[i].columnName + " " + whereMap[i].whereType + " ? AND ? "

			args = append(args, whereMap[i].whereValue[0], whereMap[i].whereValue[1])

		} else {

			whereStr += whereOrAnd
			whereOrAnd = " AND "
			whereStr += whereMap[i].columnName + " " + whereMap[i].whereType + " ? "

			args = append(args, whereMap[i].whereValue[0])

		}

	}

	return whereStr, args
}
